/**
 * 需要重写的内容:
 * 1. 属性
 * 2. 方法
 */

class XhrHooks {
    constructor(beforeHooks = {}, afterHooks = {}) {
        // beforeHooks 就是在指定的方法之前触发， 比如open事件
        // afterHooks 就是在指定的方法之后触发
        // 还是得使用原生的xhr对象
        this.XHR = window.XMLHttpRequest; // 这一步很重要
        this.beforeHooks = beforeHooks;
        this.afterHooks = afterHooks
        this.init()
    }

    init() {
        let _this = this;
        window.XMLHttpRequest = function () {
            // 利用原生的， 构造一个新的
            this._xhr = new _this.XHR()// 这里其实返回的还是一个新的自己， 最主要的是下面的这个重写操作了。
            _this.overwrite(this)
        }
    }

    overwrite(proxyXHR) {
        // 其实这里就是原生的XHR对象了
        for (let key in proxyXHR._xhr) {
            // 方法的重写
            if (typeof proxyXHR._xhr[key] === 'function') {
                // 其实这个proxyXHR就是在原生的基础上重新构建了一个新的
                // 没有在原生的XHR上面进行直接修改的
                this.overwriteMethod(key, proxyXHR)
                continue;
            }
            // 属性的重写
            this.overwriteAttributes(key, proxyXHR)
        }
    }

    overwriteMethod(key, proxyXHR) {
        let beforeHooks = this.beforeHooks;
        let afterHooks = this.afterHooks;
        // 这里类于 xhr.open() 来理解
        // 新处理这个方法， 在这个方法的基础上得干啥呢
        // 就是需要在执行方法前， 去做一些新的操作
        proxyXHR[key] = (...args) => {
            // 拦截
            if(beforeHooks[key]){
                const res = beforeHooks[key].call(proxyXHR, args)
                if(res === false) {
                    return;
                }
            }
            const res = proxyXHR._xhr.apply(proxyXHR._xhr, args)

            // 执行完成后， 触发afterHooks
            // 这样的写法只有在前面为true后, 才进行后面的操作。
            afterHooks[key] && afterHooks[key].call(proxyXHR._xhr, res)
            return res;
        }
    }

    overwriteAttributes(key, proxyXHR) {
        // 参数一： 监测的对象
        // 参数二： 监测对象中的某个属性
        // 参数三： 执行的操作
        Object.defineProperties(proxyXHR,
            this.setPropertyDescriptor(key, proxyXHR)
        )
    }
    setPropertyDescriptor(key, proxyXHR){
        let obj = Object.create(null)
        let _this = this;
        obj.set = function (val){
            if(!key.startsWith('on')){
                proxyXHR['__'+key] = val;
                return;
            }
            if(_this.beforeHooks[key]){
                this._xhr[key] = function (...args) {
                    _this.beforeHooks[key].call(args)
                    val.apply(proxyXHR, args)
                }
                return;
            }
            this._xhr[key] = val;
        }
        obj.get = function (){
            return proxyXHR['__'+key] || this._xhr[key];
        }

        return obj;
    }

}




// 这里数据
new XhrHooks({
    open() {
        console.log('open start')
    },
    send() {
        console.log('send start')
    },
    onreadystatechange() {
        console.log('onload start')
    },
    onerror() {
        console.log('onerror start')
    }
}, {
    open() {
        console.log('open end')
    },
    send() {
        console.log('send end')
    },
    onreadystatechange() {
        console.log('onload end')
    },
    onerror() {
        console.log('onerror end')
    }
})

const xhr = new XMLHttpRequest()
// xhr.open('http://www.baidu.com')

console.log(xhr)
